package com.ruoyi.user.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.user.domain.UserOrder;
import com.ruoyi.user.model.Constant;
import com.ruoyi.user.service.IUserOrderService;
import com.ruoyi.user.service.impl.RefundInfoService;
import com.ruoyi.user.utils.AESUtil;
import com.ruoyi.user.utils.DateUtils;
import com.ruoyi.user.utils.PayChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import weixin.popular.bean.paymch.MchBaseResult;
import weixin.popular.bean.paymch.MchPayNotify;
import weixin.popular.support.ExpireKey;
import weixin.popular.support.expirekey.DefaultExpireKey;
import weixin.popular.util.SignatureUtil;
import weixin.popular.util.StreamUtils;
import weixin.popular.util.XMLConverUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.logging.Logger;

/**
 * 微信支付回调通知控制器
 * 处理微信支付成功、退款等回调通知
 *
 * @author houyong
 */
@Controller
@RequestMapping("/notice")
@RefreshScope
public class WxNoticeController {

    //重复通知过滤
    private static final ExpireKey expireKey = new DefaultExpireKey();
    private final Logger logger = Logger.getLogger(WxNoticeController.class.getName());

    @Value("${weixin.native.mchkey}")
    public String wxNativeMchKey;//= "Qzsh2NG7NekKxdqaDPaPMZVfdCFtoGRM";

    @Autowired
    private IUserOrderService userOrderService;

    @Autowired
    private RefundInfoService refundInfoService;

    /**
     * mch 支付、代扣异步通知签名验证失败后 返回给微信侧的内容
     *
     * @param response HttpServletResponse对象
     * @throws IOException IO异常
     */
    private void wxPayNotifyValidateSignError(HttpServletResponse response) throws IOException {
        MchBaseResult baseResult = new MchBaseResult();
        baseResult.setReturn_code("FAIL");
        baseResult.setReturn_msg("ERROR");
        response.getOutputStream().write(XMLConverUtil.convertToXML(baseResult).getBytes());
    }

    /**
     * 微信原生支付成功回调
     *
     * @param request  HttpServletRequest对象
     * @param response HttpServletResponse对象
     */
    @RequestMapping("/web/wx/webhooks")
    @ResponseBody
    public void weixinNotice(HttpServletRequest request, HttpServletResponse response) {
        try {
            String xmlData = StreamUtils.copyToString(request.getInputStream(), Charset.forName(Constant.UTF8_ENCODING));
            Map<String, String> mapData = XMLConverUtil.convertToMap(xmlData);
            MchPayNotify payNotify = XMLConverUtil.convertToObject(MchPayNotify.class, xmlData);
            logger.info("xmlData====================>" + JSONObject.toJSON(payNotify));
            if (expireKey.exists(payNotify.getTransaction_id())) {
                return;
            }
            payNotify.buildDynamicField(mapData);
            if (SignatureUtil.validateSign(mapData, wxNativeMchKey)) {
                expireKey.add(payNotify.getTransaction_id());
                logger.info("微信支付成功返回结果集：=======》" + JSON.toJSONString(payNotify));
                BigDecimal amount = (BigDecimal.valueOf(payNotify.getTotal_fee())).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);
                Long wxPayTime = DateUtils.str2Long(payNotify.getTime_end(), DateUtils.PATTERN_7);
                UserOrder allOrder = userOrderService.findOrderByOrderId(payNotify.getOut_trade_no());
                allOrder.setChannel(PayChannel.ChannelType.WX.getValue());
                allOrder.setTradeType(payNotify.getTrade_type());
                allOrder.setPayTime(wxPayTime);
                //回填金额
                allOrder.setAmount(payNotify.getTotal_fee());
                //allOrder.setFee(payNotify.getTotal_fee());
                allOrder.setResult(JSON.toJSONString(payNotify));
                //用户的openid存到数据库中用于过期订单的退款（通过这个openid走转账的方式）
                allOrder.setBuyerId(payNotify.getOpenid());
                //支付状态更新
                allOrder.setStatus(PayChannel.TransactionStatus.PAYSUCCESS.getValue());
                allOrder.setTransactionId(payNotify.getTransaction_id());
                allOrder.setOpenid(payNotify.getOpenid());
                userOrderService.thirdPaySuccess(allOrder, payNotify.getTotal_fee(), wxPayTime);
                MchBaseResult baseResult = new MchBaseResult();
                baseResult.setReturn_code("SUCCESS");
                baseResult.setReturn_msg("OK");
                response.getOutputStream().write(XMLConverUtil.convertToXML(baseResult).getBytes());
            } else {
                wxPayNotifyValidateSignError(response);
            }
        } catch (Exception e) {
            logger.severe("处理微信支付回调异常: " + e.getMessage());
            e.printStackTrace();
            MchBaseResult baseResult = new MchBaseResult();
            baseResult.setReturn_code("FAIL");
            baseResult.setReturn_msg("ERROR");
            try {
                response.getOutputStream().write(XMLConverUtil.convertToXML(baseResult).getBytes());
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

    /**
     * 微信原生支付 退款结果通知
     *
     * @param request  HttpServletRequest对象
     * @param response HttpServletResponse对象
     */
    @RequestMapping("/web/wx/native/refund/webhooks")
    @ResponseBody
    public void weixinNativeRefundNotice(HttpServletRequest request, HttpServletResponse response) {
        try {
            InputStream inputStream = request.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inputStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            outSteam.close();
            inputStream.close();
            String result = outSteam.toString(Constant.UTF8_ENCODING);// 获取微信调用我们notify_url的返回信息
            Map<String, String> stringStringMap = XMLConverUtil.convertToMap(result);
            String req_info = stringStringMap.get("req_info");
            String s = AESUtil.decryptData(req_info);
            Map<String, String> resultMap = XMLConverUtil.convertToMap(s);
            logger.info("wx native refund webhooks resultmap" + JSON.toJSON(resultMap));
            if (expireKey.exists(resultMap.get("refund_id"))) {
                return;
            }
            expireKey.add(resultMap.get("refund_id"));
            refundInfoService.refundForWxNativeNotice(resultMap);
            MchBaseResult baseResult = new MchBaseResult();
            baseResult.setReturn_code("SUCCESS");
            baseResult.setReturn_msg("OK");
            response.getOutputStream().write(XMLConverUtil.convertToXML(baseResult).getBytes());
        } catch (Exception e) {
            logger.severe("处理微信退款回调异常: " + e.getMessage());
            e.printStackTrace();
            MchBaseResult baseResult = new MchBaseResult();
            baseResult.setReturn_code("FAIL");
            baseResult.setReturn_msg("ERROR");
            try {
                response.getOutputStream().write(XMLConverUtil.convertToXML(baseResult).getBytes());
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
    }
}